package com.itaq.cheetah.serviceA.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.itaq.cheetah.serviceA.config.http.HttpRequest;
import com.itaq.cheetah.serviceA.config.redis.RedisConstants;
import com.itaq.cheetah.serviceA.model.dto.SsoJumpReq;
import com.itaq.cheetah.serviceA.model.dto.SsoRespDto;
import com.itaq.cheetah.serviceA.model.entity.SsoClientDetail;
import com.itaq.cheetah.serviceA.model.result.WrapperResult;
import com.itaq.cheetah.serviceA.model.vo.SsoUserInfo;
import com.itaq.cheetah.serviceA.model.vo.UserInfo;
import com.itaq.cheetah.serviceA.service.ISsoClientDetailService;
import com.itaq.cheetah.serviceA.utils.JsonUtils;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 门户端单点登录
 *
 * @author cheetah
 * @date 2023/5/30
 */
@Slf4j
@RestController
@AllArgsConstructor
public class PortalController {

    private final RedisTemplate redisTemplate;

    private final ISsoClientDetailService iSsoClientDetailService;


    /**
     *
     * title：跳转 ServiceB
     * <pre>
     * 1. 前端点击Jump链接触发此接口调用
     * 2. 此接口生成ticket并携带着请求 ServiceB
     *      2.1 ServiceB拿着ticket请求我方服务获取用户信息
     *      2.2 ServiceB获取到我方用户信息并进行数据同步
     *      2.3 ServiceB返回一个链接，连接中带 token
     * 3. 重定向到返回的链接实现登录
     * </pre>
     *
     * @param req 单点跳转请求体
     * @return ServiceB单点登录地址
     */
    @PostMapping("/jumpB")
    public WrapperResult<String> jump(@RequestBody @Validated SsoJumpReq req) {
        log.debug("单点登录：{}", req.getPlatformName());
        //1、判断该平台名称是否存在
        SsoClientDetail one = iSsoClientDetailService.getOne(
                new LambdaQueryWrapper<SsoClientDetail>().eq(SsoClientDetail::getPlatformName, req.getPlatformName())
        );
        if (Objects.isNull(one)) {
            return WrapperResult.faild("不存在的app");
        }
        //2、校验本系统的 token，并从中获取用户信息
        /*
        * 示例
        * Result<Token> result = authorizationApi.checkToken(req.getToken());
        */

        //生成ticket，并将用户信息与其绑定存入redis
        String ticket = UUID.randomUUID().toString().replaceAll("-", "");
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1L);
        userInfo.setUsername("阿Q");
        redisTemplate.opsForValue().set(RedisConstants.TICKET_PREFIX + ticket, userInfo, 5, TimeUnit.MINUTES);

        String ssoUrl = one.getSsoUrl();
        Map<String, Object> data = new HashMap<>(1);
        data.put("ticket", ticket);
        //发送http请求，把ticket通过设置好的ssoUrl传给ServiceB
        WrapperResult<SsoRespDto> ssoRespDto = HttpRequest
                .get(ssoUrl)
                .queryMap(data)
                .connectTimeout(Duration.ofSeconds(120))
                .readTimeout(Duration.ofSeconds(120))
                .execute()
                .asValue(new TypeReference<WrapperResult<SsoRespDto>>() {
                });
        log.info("请求ServiceB 结果：{}", JsonUtils.toPrettyString(ssoRespDto));
        return WrapperResult.success(ssoRespDto.getData().getRedirectUrl());
    }


    /**
     *  根据票据获取用户信息
     *
     * @param ticket 票据信息
     * @return 用户信息
     */
    @ApiOperation("根据ticket获取用户信息")
    @GetMapping("/getUser")
    public WrapperResult<SsoUserInfo> loginByTicket(@RequestParam("ticket") String ticket) {
        log.info("收到票据：{}", ticket);
        UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(RedisConstants.TICKET_PREFIX + ticket);
        if (Objects.isNull(userInfo)) {
            return WrapperResult.faild("无法识别的票据信息");
        }
        //可能 userInfo 中只有少量的用户信息，此处省略了根据用户id查询用户和企业信息的过程，自行编写逻辑代码即可

        SsoUserInfo ssoUserInfo = new SsoUserInfo();
        BeanUtil.copyProperties(userInfo,ssoUserInfo);
        return WrapperResult.success(ssoUserInfo);
    }

}
